// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package ssa

import (
	"cmd/internal/src"
	"fmt"
)

type lineRange struct {
	first, last uint32
}

// xposmap是来自fileindex和src行的映射。XPos到int32，
// 稀疏实现以节省空间（忽略列和语句状态）。
// 稀疏骨架构造一次，然后被ssa阶段重新使用
// 即（重新）移动附加语句的值。
type xposmap struct {
	// 从文件索引到从行范围到整数（块号）的映射
	maps map[int32]*biasedSparseMap
	// 接下来的两个字段为同一文件中重复行的常见情况提供了单项缓存。
	lastIndex int32            // /-1表示缓存中没有条目
	lastMap   *biasedSparseMap // maps[lastIndex]
}

// newXposmap构造一个xposmap，该xposmap对以下输入有效：文件索引位于x、
// 键中，行号在x[file index]范围内。
// 如果调用方试图设置或添加不在该范围内的XPos，则生成的xposmap将死机。
func newXposmap(x map[int]lineRange) *xposmap {
	maps := make(map[int32]*biasedSparseMap)
	for i, p := range x {
		maps[int32(i)] = newBiasedSparseMap(int(p.first), int(p.last))
	}
	return &xposmap{maps: maps, lastIndex: -1} // 0表示其余的一切正常
}

// clear从地图中删除数据，但保留稀疏的骨架。
func (m *xposmap) clear() {
	for _, l := range m.maps {
		if l != nil {
			l.clear()
		}
	}
	m.lastIndex = -1
	m.lastMap = nil
}

// mapFor返回给定文件索引的行范围映射。
func (m *xposmap) mapFor(index int32) *biasedSparseMap {
	if index == m.lastIndex {
		return m.lastMap
	}
	mf := m.maps[index]
	m.lastIndex = index
	m.lastMap = mf
	return mf
}

// set将p->v插入地图。
// 如果p不在用于构造m的fileindex->lineRange集合内，这将导致死机。
func (m *xposmap) set(p src.XPos, v int32) {
	s := m.mapFor(p.FileIndex())
	if s == nil {
		panic(fmt.Sprintf("xposmap.set(%d), file index not found in map\n", p.FileIndex()))
	}
	s.set(p.Line(), v)
}

// get返回与p的文件索引和行关联的int32。
func (m *xposmap) get(p src.XPos) int32 {
	s := m.mapFor(p.FileIndex())
	if s == nil {
		return -1
	}
	return s.get(p.Line())
}

// add将p添加到m，将m视为一个集合，而不是一个映射。
// 如果p不在用于构造m的fileindex->lineRange集合内，这将导致死机。
// 在m的集合/映射解释之间使用clear（）。
func (m *xposmap) add(p src.XPos) {
	m.set(p, 0)
}

// 包含返回p的文件索引和行是否在m中，
// 将m视为集合而不是映射。
func (m *xposmap) contains(p src.XPos) bool {
	s := m.mapFor(p.FileIndex())
	if s == nil {
		return false
	}
	return s.contains(p.Line())
}

// remove从m中删除p的文件索引和行，
// 当前是否将m视为映射或集合。
func (m *xposmap) remove(p src.XPos) {
	s := m.mapFor(p.FileIndex())
	if s == nil {
		return
	}
	s.remove(p.Line())
}

// foreachEntry将f应用于m中的每个（文件索引、行、值）三元组。
func (m *xposmap) foreachEntry(f func(j int32, l uint, v int32)) {
	for j, mm := range m.maps {
		s := mm.size()
		for i := 0; i < s; i++ {
			l, v := mm.getEntry(i)
			f(j, l, v)
		}
	}
}
